package com.framework.admin.schedule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.framework.admin.schedule.constant.ScheduleConstants;
import com.framework.admin.schedule.entity.SysJob;
import com.framework.admin.schedule.entity.SysJobLog;
import com.framework.admin.schedule.mapper.JobMapper;
import com.framework.admin.schedule.param.JobParam;
import com.framework.admin.schedule.service.IJobService;
import com.framework.admin.schedule.service.ISysJobLogService;
import com.framework.admin.schedule.util.ScheduleUtils;
import com.framework.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;

@Slf4j
@Service
public class JobService implements IJobService {
    @Autowired
    private ISysJobLogService sysJobLogService;

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private JobMapper jobMapper;

    @PostConstruct
    private void resetStatus() {
        QueryWrapper<SysJob> wrapper = new QueryWrapper();
        wrapper.eq("status", "1");
        List<SysJob> jobs = jobMapper.selectList(wrapper);
        jobs.forEach(it -> {
            it.setStatus("0");
            jobMapper.updateJob(it);
        });
    }


    @Override
    public Page<SysJob> listJobs(JobParam param, Page request) {
        Page<SysJob> page = jobMapper.selectJobList(request, param);
        return page;
    }

    @Override
    public void addJob(SysJob job) {
        jobMapper.insertJob(job);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void schedulerJob(Long id) throws SchedulerException {
        SysJob job = jobMapper.selectById(id);
        String jobGroup = job.getJobGroup();
        JobKey jobKey = ScheduleUtils.getJobKey(job.getJobId(), jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (null == jobDetail) {
            job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
            startByJobObject(job);
            return;
        }
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobDetail.getKey());
        boolean isPaused = false;
        for (Trigger trigger : triggers) {
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            if (Trigger.TriggerState.PAUSED.equals(triggerState)) {
                isPaused = true;
            }
        }
        if (isPaused) {
            resumeByJobObject(job);
        } else {
            stopJob(job);
        }
    }

    private void resumeByJobObject(SysJob job) {
        SysJobLog sysJobLog = new SysJobLog();
        BeanUtils.copyProperties(job, sysJobLog);

        try {
            String jobGroup = job.getJobGroup();
            JobKey jobKey = ScheduleUtils.getJobKey(job.getJobId(), jobGroup);
            scheduler.resumeJob(jobKey);
            job.setStatus("1");
            jobMapper.updateJob(job);

            sysJobLog.setStatus("1");
            sysJobLog.setJobMessage("恢复任务失败");
        } catch (Exception e) {
            sysJobLog.setStatus("0");
            sysJobLog.setJobMessage("恢复任务失败："+e.getMessage());
            throw new BusinessException("恢复任务失败");
        }

        sysJobLogService.addJobLog(sysJobLog);
    }

    @Transactional(rollbackFor = Exception.class)
    public void stopJob(SysJob job) {
        SysJobLog sysJobLog = new SysJobLog();
        BeanUtils.copyProperties(job, sysJobLog);

        String jobGroup = job.getJobGroup();
        try {
            scheduler.pauseJob(ScheduleUtils.getJobKey(job.getJobId(), jobGroup));
            job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
            jobMapper.updateJob(job);

            sysJobLog.setStatus("1");
            sysJobLog.setJobMessage("暂停任务失败");
        } catch (SchedulerException e) {
            sysJobLog.setStatus("0");
            sysJobLog.setJobMessage("暂停任务失败："+e.getMessage());
            throw new BusinessException("暂停任务失败");
        }

        sysJobLogService.addJobLog(sysJobLog);
        log.info("任务（{}）停止成功！", job.getJobName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startJob(Long id) {
        SysJob job = jobMapper.selectById(id);
        startByJobObject(job);
    }

    private void startByJobObject(SysJob job) {
        SysJobLog sysJobLog = new SysJobLog();
        BeanUtils.copyProperties(job, sysJobLog);

        try {
            ScheduleUtils.createScheduleJob(scheduler, job);
            job.setStatus("1");
            jobMapper.updateJob(job);
            sysJobLog.setStatus("1");
            sysJobLog.setJobMessage("创建成功");
        } catch (Exception e) {
            sysJobLog.setStatus("0");
            sysJobLog.setJobMessage("创建失败："+e.getMessage());
            throw new BusinessException("创建任务失败");
        }

        sysJobLogService.addJobLog(sysJobLog);
    }

    @Override
    public void deleteJob(Long id) {
        SysJob job = jobMapper.selectById(id);
        String jobGroup = job.getJobGroup();
        jobMapper.deleteById(id);

        JobKey jobKey = ScheduleUtils.getJobKey(id, jobGroup);
        try {
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);
            }
        } catch (SchedulerException e) {
            throw new BusinessException("删除任务失败");
        }
    }

    @Override
    public boolean run(SysJob job) {
        SysJobLog sysJobLog = new SysJobLog();
        BeanUtils.copyProperties(job, sysJobLog);

        boolean result = false;
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        SysJob properties = jobMapper.selectById(job.getJobId());
        // 参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        try {
            if (scheduler.checkExists(jobKey)) {
                result = true;
                scheduler.triggerJob(jobKey, dataMap);
            }
            sysJobLog.setStatus("1");
            sysJobLog.setJobMessage("任务执行成功");
        } catch (SchedulerException e) {
            sysJobLog.setStatus("0");
            sysJobLog.setJobMessage("任务执行失败："+e.getMessage());
            throw new BusinessException("任务执行失败");
        }
        sysJobLogService.addJobLog(sysJobLog);
        return result;
    }

    @Override
    public void updateJob(SysJob job) {
        jobMapper.updateJob(job);
        try {
            JobKey jobKey = ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup());
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);
            }
            ScheduleUtils.createScheduleJob(scheduler, job);
        } catch (Exception e) {
            log.error("修改任务失败！");
        }

        if (!job.getMisfirePolicy().equals(ScheduleConstants.MISFIRE_DO_NOTHING) && job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
            run(job);
        }
    }

    @Override
    public SysJob getJob(Long id) {
        return jobMapper.selectById(id);
    }
}
